package propertie

import (
	"bufio"
	"fmt"
	"io"
	"io/fs"
	"io/ioutil"
	"os"
	"strings"
	"sync"
)

type Properties struct {
	path   string
	config sync.Map
	file   *os.File
}

func Init(path string) *Properties {
	prop := &Properties{path: path}
	prop.openFile()
	prop.initReadFile()
	return prop
}

func (m *Properties) openFile() *os.File {
	file, err := os.OpenFile(m.path, os.O_RDWR|os.O_CREATE, os.ModePerm)
	if err != nil {
		fmt.Println("open file error:", err.Error())
		return nil
	}
	m.file = file
	return m.file
}

func (m *Properties) initReadFile() {
	srcReader := bufio.NewReader(m.file)
	for {
		line, _, err := srcReader.ReadLine()
		if err != nil {
			if err == io.EOF {
				break
			}
		}
		if 0 == len(line) {
			continue
		}
		data := strings.Split(string(line), "=")
		if len(data) == 2 {
			key := strings.Replace(data[0], " ", "", -1)
			val := strings.Replace(data[1], " ", "", -1)
			m.config.Store(strings.Replace(key, "\n", "", -1), strings.Replace(val, "\n", "", -1))
		}
	}
}

func (m *Properties) readFile() string {
	srcReader := bufio.NewReader(m.file)
	var data = ""
	for {
		line, _, err := srcReader.ReadLine()
		if err != nil {
			if err == io.EOF {
				break
			}
		}
		if 0 == len(line) {
			continue
		}
		data += string(line) + "\r\n"
	}
	return data
}

func (m *Properties) Close() {
	if m.file != nil {
		m.file.Close()
		m.file = nil
	}
}
func (m *Properties) GetProperties(key string) string {
	if val, ok := m.config.Load(key); ok {
		return val.(string)
	}
	return ""
}

func (m *Properties) SetProperties(key, value string) {
	oldVal := m.GetProperties(key)
	m.config.Store(key, value)
	m.write(key, oldVal, value)
}

func (m *Properties) Is(key string) bool {
	_, b := m.config.Load(key)
	return b
}

func (m *Properties) write(key, oldValue, newValue string) {
	newKeyValue := key + "=" + newValue
	if oldValue == "" {
		ioutil.WriteFile(m.path, []byte(newKeyValue), fs.ModeAppend)
		return
	}
	var data = m.readFile()
	if data != "" {
		oldKeyValue := key + "=" + oldValue
		data = strings.Replace(data, oldKeyValue, newKeyValue, -1)
		err := os.Truncate(m.path, 0)
		if err != nil {
			fmt.Println("write-【truncate file error】:", err.Error())
		} else {
			ioutil.WriteFile(m.path, []byte(data), fs.ModePerm)
		}
	} else {
		ioutil.WriteFile(m.path, []byte(newKeyValue), fs.ModePerm)
	}
}
